#include "stdafx.h"
#include "PluginInterface.h"
#include "PluginManager.h"

using namespace MomogenkyouSystem;

std::map<std::string,	PluginContainer>	PluginManager::g_Plugins;

void	PluginManager::Initialize()
{

}

void	PluginManager::Shutdown()
{
	PluginManager::UnloadAllPlugin();
}


void *	PluginManager::LoadPlugin(const std::string & ExtensionName)
{
	std::string		_ExtName = System_Utility::LowerCase(ExtensionName);
	
	std::map<std::string, PluginContainer>::iterator it = g_Plugins.find(_ExtName);
	if(it != g_Plugins.end())
	{
		WriteCommandLine("PluginManager > Warning : Indentical DLL loaded %s", _ExtName.c_str());
		return it->second.ReferencePtr;
	}
	PluginContainer	_Container;

	_Container.DLLModuleHandle = LoadLibraryA(_ExtName.c_str());
	if(_Container.DLLModuleHandle == NULL)
	{
		WriteCommandLine("PluginManager > Error : Problem loading DLL %s ", _ExtName.c_str());
		return NULL;
	}

	//	Function Pointer 
	//	@param	Directiory
	//	@param	App Width
	//	@param	App	Height
	//	Possibly @param EventHandler to pass events back to app

	typedef	PluginInterface	*	(* PluginFunctionPtr)(std::string, int, int);

	PluginFunctionPtr	_GetReference(NULL);

	_GetReference	= (PluginFunctionPtr)GetProcAddress(_Container.DLLModuleHandle, "GetReference");
	if(_GetReference == NULL)
	{
		WriteCommandLine("PluginManager > Error : Problem in GetReference in DLL %s ", _ExtName.c_str());
		FreeLibrary(_Container.DLLModuleHandle);
		return NULL;
	}
	
	_Container.ReferencePtr =	_GetReference(APP_PLUGIN_FOLDER,	GraphicsSystem::ViewPort.Width, GraphicsSystem::ViewPort.Height);

	it = g_Plugins.insert(g_Plugins.begin(), std::pair<std::string, PluginContainer>(_ExtName, _Container));
	_Container.ReferencePtr = NULL;

	_GetReference = NULL;
	return it->second.ReferencePtr;
}

PluginContainer*	PluginManager::GetPlugin(const std::string & ExtensionName)
{
	std::string		_ExtName = System_Utility::LowerCase(ExtensionName);

	std::map<std::string, PluginContainer>::iterator it = g_Plugins.find(_ExtName);
	if(it != g_Plugins.end())
	{
		return &it->second;
	}
	return NULL;
}

void	PluginManager::UnloadPlugin(const std::string & ExtensionName)
{
	std::string		_ExtName = System_Utility::LowerCase(ExtensionName);
	std::map<std::string, PluginContainer>::iterator it = g_Plugins.find(_ExtName);
	ASSERT(it != g_Plugins.end(), "Extension does not exist");

	typedef void ( * PluginFunctionPtr)(PluginInterface *);
	PluginFunctionPtr _RemoveReference =  (PluginFunctionPtr)GetProcAddress(it->second.DLLModuleHandle, "RemoveReference");
	_RemoveReference((PluginInterface *)it->second.ReferencePtr);

	FreeLibrary(it->second.DLLModuleHandle);
	it->second.DLLModuleHandle = NULL;
	it->second.ReferencePtr = NULL;
	g_Plugins.erase(it);

	WriteCommandLine("PluginManager > DLL Successfully Removed %s", _ExtName.c_str());
	_RemoveReference = NULL;		
}

void	PluginManager::UnloadAllPlugin()
{
	for(std::map<std::string, PluginContainer>::iterator it = g_Plugins.begin();
		it != g_Plugins.end(); it++)
	{

		typedef void ( * PluginFunctionPtr)(PluginInterface *);
		PluginFunctionPtr _RemoveReference =  (PluginFunctionPtr)GetProcAddress(it->second.DLLModuleHandle, "RemoveReference");
		_RemoveReference((PluginInterface *)it->second.ReferencePtr);

		if(FreeLibrary(it->second.DLLModuleHandle))
		{
			it->second.DLLModuleHandle	= NULL;
			it->second.ReferencePtr		= NULL;
			WriteCommandLine("PluginManager > DLL Successfully Removed %s", it->first.c_str());
			continue;
		}
		WriteCommandLine("PluginManager >  ERROR : DLL Removal Error %s", it->first.c_str());
	}
	g_Plugins.clear();
	WriteCommandLine("PluginManager > All Plugins Sucessfully Removed");
}